/*
 * Copyright (c) 2007, Per Lindgren, Johan Eriksson, Johan Nordlander,
 * Simon Aittamaa.
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Luleå University of Technology nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <string.h>

#include <env.h>
#include <types.h>

#include <kernel-srp.h>

/* ************************************************************************** */

char tt_args_none = 42;

/* ************************************************************************** */

struct tt_message_t
{
	tt_message_t *next;

	/**
	 * \brief Baseline of message.
	 */
	env_time_t baseline;

	/**
	 * \brief Deadline of message.
	 */
	env_time_t deadline;

	/**
	 * \brief The object to perform the call upon.
	 */
	tt_object_t *to;

	/**
	 * \brief The method that should be called upon the given object.
	 */
	tt_method_t method;

	/**
	 * \brief The receipt for this message if any.
	 */
	tt_receipt_t *receipt;

	/**
	 * \brief The message flags.
	 */
	tt_flags_t flags;

	/**
	 * \brief TinyTimber argument buffer.
	 */
	union
	{
		/**
		 * \brief Variable length argument buffer.
		 */
		char buf[TT_ARGS_SIZE];

		/** \cond */
		void *___ptr;
		long ___long;
#if defined __STDC_VERSION__ && __STDC_VERSION >= 19991L
		long long ___long_long;
		/** \endcond */
#endif
	} arg;
};

/* ************************************************************************** */

static tt_message_t message_pool[TT_NUM_MESSAGES];

/* ************************************************************************** */

/**
 * \brief TinyTimber dequeue/pop macro.
 */
#define DEQUEUE(list, item) \
do {\
	item = list;\
	list = list->next;\
} while (0)

/* ************************************************************************** */

/**
 * \brief TinyTimber enqueue/push macro.
 */
#define ENQUEUE(list, item) \
do {\
	item->next = list;\
	list = item;\
} while (0)

/* ************************************************************************** */

/**
 * \brief TinyTimber enqueue by deadline function.
 *
 * \param list List to enqueue into.
 * \param msg Message to qneue.
 */
static ENV_CODE_FAST ENV_INLINE void enqueue_by_deadline(tt_message_t **list, tt_message_t *msg)
{
	tt_message_t *prev = NULL;
	tt_message_t *tmp = *list;

	/* Find where to insert the message. */
	while (
			tmp &&
			ENV_TIME_LE(tmp->deadline, msg->deadline)
		  ) {
		prev = tmp;
		tmp = tmp->next;
	}

	/* Insert the message into the list, check for head etc. */
	msg->next = tmp;
	if (prev) {
		prev->next = msg;
	} else {
		*list = msg;
	}
}

/* ************************************************************************** */

/**
 * \brief TinyTimber enqueue by baseline function.
 *
 * \param list List to enqueue into.
 * \param msg Message to enqueue.
 */
static ENV_CODE_FAST ENV_INLINE void enqueue_by_baseline(tt_message_t **list, tt_message_t *msg)
{
	tt_message_t *prev = NULL;
	tt_message_t *tmp = *list;

	/* Find where to place the message. */
	while (
			tmp &&
			ENV_TIME_LE(tmp->baseline, msg->baseline)
		  ) {
		prev = tmp;
		tmp = tmp->next;
	}

	/* Insert the message into the list, check for head etc. */
	msg ->next = tmp;
	if (prev) {
		prev->next = msg;
	} else {
		*list = msg;
	}
}

/* ************************************************************************** */

/**
 * \brief The TinyTimber init function.
 *
 * Should initialize the kernel to a state where async messages can be sent.
 * No timer should be running.
 *
 * \note
 *	Will call ENV_PANIC() upon failure.
 */
void tt_init(void)
{
	int i;

	/*
	 * We must always initialize the environment before anything else.
	 * Since ENV_CONTEXT_INIT() etc. might need it.
	 */
	ENV_INIT();

	TT_SANITY(ENV_ISPROTECTED());

	/*
	 * Setup the message housekeeping structure, the memset() is not
	 * neccesary in theory but in practice we will need it. The reason
	 * for this is that not all compilers honor the static
	 * initialization (namely C18).
	 */
	messages.running = NULL;
	messages.active = NULL;
	messages.inactive = NULL;
	memset(message_pool, 0, sizeof(message_pool));
	messages.free = message_pool;
	for (i=0;i<TT_NUM_MESSAGES;i++)
		message_pool[i].next = &message_pool[i+1];
	message_pool[TT_NUM_MESSAGES-1].next = NULL;

	/* Initialize all object requirements. */
	tt_objects_init();
}

